package com.chen.Sign.controller;


import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chen.Sign.common.Result;
import com.chen.Sign.pojo.User;
import com.chen.Sign.mapper.UserMapper;
import com.chen.Sign.service.impl.EmailServiceImpl;
import com.chen.Sign.service.impl.UserServiceImpl;
import com.chen.Sign.utils.FileUtils;
import com.chen.Sign.utils.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.*;
import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

// 用户模块
@Slf4j
@RestController
@CrossOrigin
@SuppressWarnings({"all"})
@RequestMapping("/user")
public class UserController {

    @Value("${lab.path}")
    private String basePath;

    @Autowired
    UserServiceImpl userService;

    @Autowired
    EmailServiceImpl emailService;

    @Autowired
    UserMapper userMapper;

    @Autowired
    RedisTemplate redisTemplate;

    // 随机生成4位验证码
    public static String getNumber() {
        String str = "123456789qwertyuiopoasdfghjklzxcvbnm";
        String code = "";
        for (int i = 0; i < 4; i++) {
            int index = (int) (Math.random() * str.length());
            code += str.charAt(index);
        }
        return code;
    }


    // JWT登录
    @PostMapping("/login")
    public Result login(HttpServletRequest request, HttpServletResponse response) {
        // 获取前端的username和password
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 实例化User对象，并进行username和password的存储
        User user = new User();
        user.setUsername(username);
        user.setPassword(DigestUtils.md5Hex(password));
        Map<String, Object> map = new HashMap<>();
        try {
            User login = userService.login(user);
            HashMap<String, String> payload = new HashMap<>();
            payload.put("id", String.valueOf(login.getId()));
            payload.put("name", login.getName());
            // 生成JWT的令牌
            String token = JWTUtils.getToken(payload);
            map.put("token", token);
            return new Result(1, "认证成功", map);
        } catch (Exception e) {
            map.put("msg", e.getMessage());
            return new Result(0, "认证失败", map);
        }
    }

    // PC端注册
    @PostMapping("/register")
    public Result register(HttpServletRequest request, HttpServletResponse response) {
        Result result = new Result();
        String username = request.getParameter("username");
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String grade2[] = request.getParameterValues("grade");
        String grade1 = Arrays.toString(grade2);
        String grade = grade1.substring(1, grade1.length() - 2);
        boolean usercheck = userService.registerCheck(name);
        Map<String, String> map = new HashMap<>();
        if (usercheck) {
            String code1 = request.getParameter("code");
            String code = (String) redisTemplate.opsForValue().get(code1);
            System.out.println(code1);
            System.out.println(code);
            if (code.equals(code1)) {
                User user = new User();
                user.setUsername(username);
                user.setName(name);
                user.setPassword(DigestUtils.md5Hex(password));
                user.setEmail(email);
                user.setGrade(grade);
                int i = userMapper.insert(user);
                if (i > 0) {
                    return result.registerok(map);
                } else {
                    return result.registerno(map);
                }
            } else {
                // 验证码错误    code 3
                return result.checkcodeno(map);
            }
        } else {
            // 用户名已经存在 code 2
            map.put("username", username);
            return result.registerusernamecheckno(map);
        }
    }

    // 小程序注册
    @PostMapping("/registerwx")
    public Result registerwx(HttpServletRequest request, HttpServletResponse response) {
        Result result = new Result();
        String username = request.getParameter("username");
        String name = request.getParameter("name");
        String password = request.getParameter("password");
        String email = request.getParameter("email");
        String grade = request.getParameter("grade");
        boolean usercheck = userService.registerCheck(username);
        Map<String, String> map = new HashMap<>();
        if (usercheck) {
            String code1 = request.getParameter("code");
            String code = (String) redisTemplate.opsForValue().get(code1);
            System.out.println(code1);
            System.out.println(code);
            if (code.equals(code1)) {
                User user = new User();
                user.setUsername(username);
                user.setName(name);
                user.setPassword(DigestUtils.md5Hex(password));
                user.setEmail(email);
                user.setGrade(grade);
                user.setPassword(DigestUtils.md5Hex(user.getPassword()));
                int i = userMapper.insert(user);
                if (i > 0) {
                    return result.registerok(map);
                } else {
                    return result.registerno(map);
                }
            } else {
                // 验证码错误    code 3
                return result.checkcodeno(map);
            }
        } else {
            // 用户名已经存在 code 2
            map.put("username", username);
            return result.registerusernamecheckno(map);
        }
    }

    // 忘记密码
    @PostMapping("/forgetpassword")
    public Result forgotpassword(HttpServletRequest request, HttpServletResponse response) {
        Result result = new Result();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String passwordAgain = request.getParameter("passwordAgain");
        boolean usercheck = userService.registerCheck(username);
        HashMap<String, String> map = new HashMap<>();
        if (usercheck) {
            // 数据库中没有该用户名的数据 code 2
            map.put("username", username);
            return Result.forgotusernamenoexist(map);
        } else {
            // 数据库中有该用户名的数据
            String code1 = request.getParameter("code");
            String code = (String) redisTemplate.opsForValue().get(code1);
            if (code.equals(code1)) {
                boolean flag = userService.updatepassword(username, DigestUtils.md5Hex(password));
                if (flag) {
                    // 修改成功 code 1
                    return result.updatepasswordok(map);
                } else {
                    // 修改失败 code 0
                    return result.updatepasswordno(map);
                }
            } else {
                // 验证码错误    code 3
                return result.checkcodeno(map);
            }
        }
    }

    //邮件发送
    @PostMapping("/mail")
    @ResponseBody
    public Result mail(HttpServletRequest request) {
        Result result = new Result();
        String code = getNumber();
        String email = request.getParameter("email");
        redisTemplate.opsForValue().set(code, code, Duration.ofMinutes(10L));
        boolean b = emailService.sendMail(email, "实验室注册验证码,有效时间为10分钟:", code);
        // 邮件发送成功
        HashMap<String, String> map = new HashMap<>();
        result.setCode(200);
        return result.mailok(map);
    }

    //忘记密码邮箱验证
    @PostMapping("/forgetmail")
    public Result forgetmail(HttpServletRequest request) {
        Result result = new Result();
        String code = getNumber();
        String email = request.getParameter("email");
        String username = request.getParameter("username");
        String useremail = userService.useremail(username);
        System.out.println(email);
        System.out.println(username);
        System.out.println(useremail);
        HashMap<String, String> map = new HashMap<>();
        if (useremail.equals(email)) {
            redisTemplate.opsForValue().set(code, code, Duration.ofMinutes(10L));
            boolean b = emailService.sendMail(email, "实验室注册验证码,有效时间为10分钟:", code);
            // 邮件发送成功
            result.setCode(200);
            return result.mailok(map);
        } else {
            // 邮箱错误     code 2
            return Result.emailnomatch(map);
        }
    }

    // 退出登录
    @PostMapping("/logout")
    public Result logout(HttpServletRequest request) {
        Result result = new Result();
        // 清理Session中保存的当前登录的用户名
        String token = request.getHeader("token");
        redisTemplate.delete(token);
        Map<String, String> map = new HashMap<>();
        return result.logoutok(map);
    }

    // 返回个人信息
    @GetMapping("/allinformatin")
    public Result allinformation(HttpServletRequest request) {
        String token = request.getHeader("token");
        DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
        Integer id = tokenInfo.getClaim("id").asInt();
        String username = tokenInfo.getClaim("username").asString();
        Result result = new Result();
        User user = userService.selectallinformation(username);
        // 代码优化
        // LambdaQueryWrapper<User> querywrapper = new LambdaQueryWrapper<>();
        // querywrapper.eq(User::getUsername,username);
        // User user = userService.getOne(querywrapper);
        Map<String, String> map = new HashMap<>();
        map.put("username", user.getUsername());
        map.put("name", user.getName());
        map.put("nickname", user.getNickname());
        map.put("sex", user.getSex());
        map.put("personalsignature", user.getPersonalsignature());
        map.put("email", user.getEmail());
        map.put("telephone", user.getTelephone());
        map.put("grade", user.getGrade());
        map.put("profession", user.getProfession());
        return result.allinformationok(map);
    }

    // 编辑个人信息
    @PutMapping("/editinformation")
    public Result editinformation(HttpServletRequest request) {
        Result result = new Result();
        String token = request.getHeader("token");
        DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
        Integer id = tokenInfo.getClaim("id").asInt();
        String username = tokenInfo.getClaim("username").asString();
        String name = request.getParameter("name");
        String nickname = request.getParameter("nickname");
        String sex2[] = request.getParameterValues("sex");
        String sex1 = Arrays.toString(sex2);
        String sex = sex1.substring(1, sex1.length() - 2);
        String personalsignature = request.getParameter("personalsignature");
        String email = request.getParameter("email");
        String telephone = request.getParameter("telephone");
        String grade2[] = request.getParameterValues("grade");
        String grade1 = Arrays.toString(grade2);
        String grade = grade1.substring(1, grade1.length() - 2);
        String profession = request.getParameter("profession");
        User user = userService.editinformation(username);
        if (user != null) {
            return result.editinformationok("");
        } else {
            return result.editinformationno("");
        }
    }

    // 上传头像、将数据保存到数据库
    @PostMapping("/uploadpp")
    public Result upload(/*@RequestPart("profile_photo")*/ MultipartFile profile_photo, HttpServletRequest request) throws IOException {
        log.info("接收到的数据,{}",profile_photo);
     /*   Result result = new Result();
        Map<String, byte[]> map = new HashMap<>();
        if (!profile_photo.isEmpty()) {
            String token = request.getHeader("token");
            DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
            Integer id = tokenInfo.getClaim("id").asInt();
            String username = tokenInfo.getClaim("username").asString();
            User user = userService.upload(username);
            String localpath = "D://signImages";
            String fileName = profile_photo.getOriginalFilename();
            String realpath = FileUtils.upload(profile_photo, localpath, fileName);
            user.setProfile_photo(realpath);
            boolean b = userService.insertProfile_photo(username, realpath);
            if (b) {
                // code 1
                return result.insertProfile_photook(map);
            } else {
                // code 0
                return result.insertProfile_photono(map);
            }
        } else {
            // 头像为空 code 3
            return result.Profile_photonoempty(map);
        }*/
        log.info(profile_photo.toString());
        String token = request.getHeader("token");
        DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
        Integer id = tokenInfo.getClaim("id").asInt();
        String username = tokenInfo.getClaim("username").asString();
        // 原始文件名
        String originalFilename = profile_photo.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        // 使用UUID重新生成文件名，防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID().toString() + suffix;

        // 创建一个目录对象，判断是否存在，不存在则创建
        File dir = new File(basePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            profile_photo.transferTo(new File(basePath + fileName));
            userService.insertProfile_photo(username, fileName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return new Result(1,"头像上传成功",fileName);
    }

    /**
     * 回显头像
     * @param name
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @GetMapping("/getpp")
    @ResponseBody
    public void getImage(String name,HttpServletRequest request,HttpServletResponse response) throws Exception {
        /*Result result = new Result();
        String token = request.getHeader("token");
        DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
        Integer id = tokenInfo.getClaim("id").asInt();
        String username = tokenInfo.getClaim("username").asString();
        User user = userMapper.selectById(id);
        String filePath = user.getProfile_photo();
        // 将图片转换为二进制
        File f = new File(filePath);
        BASE64Encoder encoder = new sun.misc.BASE64Encoder();
        BufferedImage bi;
        try {
            bi = ImageIO.read(f);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(bi, "jpg", baos);  //经测试转换的图片是格式这里就什么格式，否则会失真
            byte[] bytes = baos.toByteArray();
            return new Result(1,"头像回显成功",encoder.encodeBuffer(bytes).trim());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new Result(0,"头像回显失败","");*/

        try {
            // 输入流，通过输入流读取文件内容
            FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));

            // 输出流，通过输出流将文件写回浏览器，在浏览器展示图片
            ServletOutputStream outputStream = response.getOutputStream();

            response.setContentType("image/jpeg");

            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = fileInputStream.read(bytes)) != -1) {
                outputStream.write(bytes,0,len);
                outputStream.flush();
            }

            // 关闭资源
            outputStream.close();
            fileInputStream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 修改头像
    @PutMapping("/editpp")
    public Result editpp(@RequestPart("profile_photo") MultipartFile profile_photo, HttpServletRequest request) {
      /*  Result result = new Result();
        Map<String, byte[]> map = new HashMap<>();
        if (!profile_photo.isEmpty()) {
            String token = request.getHeader("token");
            DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
            Integer id = tokenInfo.getClaim("id").asInt();
            String username = tokenInfo.getClaim("username").asString();
            User user = userService.upload(username);
            String localpath = "D://signImages";
            String fileName = profile_photo.getOriginalFilename();
            String realpath = FileUtils.upload(profile_photo, localpath, fileName);
            user.setProfile_photo(realpath);
            boolean b = userService.insertProfile_photo(username, realpath);
            if (b) {
                // code 1
                return result.insertProfile_photook(map);
            } else {
                // code 0
                return result.insertProfile_photono(map);
            }
        } else {
            // 头像为空 code 3
            return result.Profile_photonoempty(map);
        }*/
        log.info(profile_photo.toString());
        String token = request.getHeader("token");
        DecodedJWT tokenInfo = JWTUtils.getTokenInfo(token);
        Integer id = tokenInfo.getClaim("id").asInt();
        String username = tokenInfo.getClaim("username").asString();
        // 原始文件名
        String originalFilename = profile_photo.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        // 使用UUID重新生成文件名，防止文件名称重复造成文件覆盖
        String fileName = UUID.randomUUID().toString() + suffix;

        // 创建一个目录对象，判断是否存在，不存在则创建
        File dir = new File(basePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            profile_photo.transferTo(new File(basePath + fileName));
            LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(User::getId,id).set(User::getProfile_photo,fileName);
            User user = new User();
            int update = userMapper.update(user, updateWrapper);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return new Result(1,"头像修改成功",fileName);
    }
}





